package cn.edu.lingnan.service.base.impl;

import cn.edu.lingnan.bean.Book;
import cn.edu.lingnan.repository.BookRepository;
import cn.edu.lingnan.service.base.BaseService;
import cn.hutool.core.util.StrUtil;
import org.hibernate.tuple.entity.EntityTuplizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import javax.persistence.Id;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.*;

//@Service
public class BaseServiceImpl<T, ID> implements BaseService<T, ID> {


    @Resource
    private JpaRepository<T,ID> repository;
    @Resource
    private BookRepository bookRepository;

    public Map<String, Object> page(int pageNum, int pageSize,String entity){

        Specification sp = new  Specification<Book>(){
            /**
             * toPredicate: 构造查询条件的主要方法
             *     Root: 表示可查询和操作实体对象的根，如果将实体对象比喻为表明，root则为表的字段
             *
             *     CriteriaQuery: 查询操作对象，它包含操作的各个组件部分：select、from、where、group by、order by
             *
             *     CriteriaBuilder：构造器对象，其实相当于条件或条件组件
             */

            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder criteriaBuilder) {
                Predicate predicate = null;
                //hasBlank: hutool 工具包中封装的方法
                if (!StrUtil.hasBlank(entity)){
                    predicate = criteriaBuilder.like(root.get("name").as(String.class),"%"+entity+"%");
                }
                return predicate;
            }
        };

        Map<String, Object> map = new HashMap<>();
        PageRequest pageRequest = PageRequest.of(pageNum -1, pageSize, Sort.by(Sort.Direction.DESC,"id"));
        Page<Book> page = bookRepository.findAll(sp,pageRequest);
        map.put("TotalElements",page.getTotalElements());
        map.put("pageContent",page.getContent());
        return map;
    }




    @Override
    public Map<String, Object> page(int pageNum, int pageSize, T entity) {
        HashMap<String, Object> map = new HashMap<>();
        PageRequest pageRequest = PageRequest.of(pageNum -1, pageSize);
        Example<T> example = Example.of(entity);
        Page<T> page = repository.findAll(example,pageRequest);
        map.put("TotalElements",page.getTotalElements());
        map.put("pageContent",page.getContent());
        return map;
    }

    @Override
    public Map<String, Object> page(int pageNum, int pageSize) {
        HashMap<String, Object> map = new HashMap<>();
        PageRequest pageRequest = PageRequest.of(pageNum -1, pageSize);
      // Example<T> example = Example.of(entity);
        Page<T> page = repository.findAll(pageRequest);
        map.put("TotalElements",page.getTotalElements());
        map.put("pageContent",page.getContent());
        return map;
    }



    @Override
    public List<T> selectAll() {
        return repository.findAll();
    }

    @Override
    public Optional<T> selectById(ID id) {
        return repository.findById(id);
    }

    @Override
    public T save(T entity) {
        return repository.save(entity);
    }

    @Override
    public List<T> saveBatch(List<T> entity) {
        return repository.saveAll(entity);
    }

    @Override
    public void deleteById(ID id) {
        repository.deleteById(id);
    }

    @Override
    public void deleteBatch(ID[] ids) {
        List list = new ArrayList<>();
        for(ID id:ids){
            list.add(id);
        }
        repository.deleteInBatch(list);
    }

    @Override
    public T update(T entity, ID id) {
        return repository.save(entity);
    }
}
